/*
Autor: Alexander Savochkin, 2010
New BSD License
*/

#pragma once

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lexical_cast.hpp>

#include <boost/log/common.hpp>

#include "LogDefinitions.h"

#include <map>
#include <vector>

#include "Manager.h"

using boost::asio::ip::tcp;	// <- it is class but not namespace
using namespace boost::posix_time;
using namespace boost::asio;
using std::vector;
using boost::shared_ptr;
using boost::lexical_cast;

namespace SRCLF {
namespace Server {

	class ClientConnection 
	{
		ClientInfo client_info;
	public:
		ClientConnection(boost::asio::io_service& _io_service, ClientId client_id, unsigned tcp_port, 
			boost::function1<void, ClientConnection* > _receiveHandler,
			boost::function1<void, ClientConnection* > _errorHandler) : client_info("tcp:"+lexical_cast<string>(tcp_port), client_id),
			receiveHandler(_receiveHandler), errorHandler(_errorHandler),
				socket(_io_service)
		{
		}

		void start()
		{
			receiveNextCommand();
		}

		const ClientInfo & getClientInfo() const { return client_info; };

		void receiveNextCommand()
		{
			//Continue read new commands		
			boost::asio::async_read_until(socket, command_buffer, '\n', 
				boost::bind(&ClientConnection::receiveLineHandle, this, boost::asio::placeholders::error) );
		}

		void getReceivedCommand(string& received_command);

		void receiveLineHandle(const boost::system::error_code& error);

		bool needClose() const
		{
			return need_close;
		}

		tcp::socket& getSocket()
		{
			return socket;
		}

		void writeResponce(const string& response);

		void writeHandler(const boost::system::error_code& error);

	private:
		bool need_close;
		boost::function1<void, ClientConnection* > receiveHandler;
		boost::function1<void, ClientConnection* > errorHandler;
		tcp::socket socket;
		boost::asio::streambuf command_buffer;
	};

	/**
	@class TCPServer
	@brief This class represents TCP server.
	*/
	class TCPServer
	{
		boost::log::sources::severity_logger< severity_level > logger;
	public:
		/**
		@brief Constructor
		@param _io_service
		@param _control_loop_manager
		@param config
		*/	  
		TCPServer(boost::asio::io_service& _io_service, Manager& _control_loop_manager, const Configuration& config);

		void getFutureControlActionTime( ptime& next_control_time ) const;

	private:
		void onAccept(size_t index, unsigned tcp_port, const boost::system::error_code& e, 
			ClientConnection* new_connection);
		void onCloseConnection(ClientConnection *connection);
		void onNewCommand(ClientConnection *connection);

		void createAcceptor(unsigned tcp_port);

		vector<shared_ptr<tcp::acceptor> > acceptors;
		ptime future_regular_action_moment;

		boost::asio::io_service& io_service;
		boost::asio::deadline_timer timer;

		Manager &control_loop_manager;
	};

} //namespace Server
} //namespace SRCLF
